import { mapCompositionCoordArr } from './mapCompositionCoord.util'

const BASE_UNIT = 100
export const mapMashupCoord = (mashup) => {
  const { structure, align } = mashup
  const groups = scaleGroupsNumber(mashup.groups, BASE_UNIT)

  let innerCoords = [];
  groups.forEach(group => {
    const inCoords = getInnerCoords(group)
    const size = calcBoundSize(inCoords)
    innerCoords.push(inCoords)
  })

  const calcCoords = {
    'coordinate': calcCoordGroups,
    'horizontal': calcHorizGroups,
    'vertical': calcVerticalGroups,
  }
  const groupsCoords = calcCoords[structure](groups, innerCoords)

  let coordinates = mapInnerCoordsToGroups(innerCoords, groupsCoords)
  return coordinates;
}

function calcCoordGroups(groups, innerCoords) {
  let groupsCoords = []
  groups.forEach((group, index) => {
    let { width, height } = calcBoundSize(innerCoords[index])
    const boundSize = calcBoundSize(innerCoords[index])
    const scale = group.size / boundSize[group.based]
    width *= scale
    height *= scale
    const x = group.left
    const y = group.top
    groupsCoords.push({ x, y, width, height })
  })
  return groupsCoords
}

function calcVerticalGroups(groups, innerCoords) {
  let groupsCoords = []
  let baseCoord = { x: 0, y: 0 }
  const maxSize = _findMaxSizeFromGroups(groups, innerCoords, 'width')
  groups.forEach((group, index) => {
    let { width, height } = calcBoundSize(innerCoords[index])
    const boundSize = calcBoundSize(innerCoords[index])
    const scale = group.size / boundSize[group.based]
    width *= scale
    height *= scale
    baseCoord.x = (maxSize - group.size) / 2
    baseCoord.y += group.marginTop
    groupsCoords.push({ ...baseCoord, width, height })
    baseCoord.y += (height + group.marginBottom)
  })
  return groupsCoords
}

function calcHorizGroups(groups, innerCoords) {
  let groupsCoords = []
  let baseCoord = { x: 0, y: 0 }
  const maxSize = _findMaxSizeFromGroups(groups, innerCoords, 'height')
  groups.forEach((group, index) => {
    let { width, height } = calcBoundSize(innerCoords[index])
    const boundSize = calcBoundSize(innerCoords[index])
    const scale = group.size / boundSize[group.based]
    width *= scale
    height *= scale
    baseCoord.x += group.marginLeft
    baseCoord.y = (maxSize - group.size) / 2
    groupsCoords.push({ ...baseCoord, width, height })
    baseCoord.x += (width + group.marginRight)
  })
  return groupsCoords
}

function mapInnerCoordsToGroups(innerCoords, groupsCoords) {
  // innerCoords: [[], []]
  const coordinates = []
  innerCoords.forEach((coords, index) => {
    const groupCoord = groupsCoords[index]
    const groupWidth = groupCoord.width
    const innerWidth = calcBoundSize(coords).width
    const scale = groupWidth / innerWidth
    coords.forEach(coord => {
      const x = groupCoord.x + coord.x * scale
      const y = groupCoord.y + coord.y * scale
      const width = coord.width * scale
      const height = coord.height * scale
      const graphicId = coord.graphicId
      coordinates.push({ x, y, width, height, graphicId })
    })
  })
  return coordinates
}

function _findMaxSizeFromGroups(groups, innerCoords, side) {
  let maxSize = 0
  groups.forEach((group, index) => {
    const item = { width: 0, height: 0 }
    const groupSize = innerCoords[index]
    const groupAspectRatio = groupSize.width / groupSize.height
    if (group.based === 'width') {
      item.width = group.size
      item.height = item.width / groupAspectRatio
    } else {
      item.height = group.size
      item.width = item.height * groupAspectRatio
    }
    maxSize = item[side] > maxSize ? item[side] : maxSize
  });
  return maxSize
}

function getInnerCoords(item) {
  const process = {
    graphic: item => {
      const { width, height } = _extractViewBox(item.svgCode);
      return [{ x: 0, y: 0, width, height, graphicId: item.graphicId }]
    },
    composition: item => {
      const coordinates = mapCompositionCoordArr(item.composition)
      return coordinates
    },
  }
  return process[item.type](item)
}

function _extractViewBox(svgCode = '') {
  const viewBoxRegex = /viewBox="([^"]+)"/;
  const match = svgCode.match(viewBoxRegex);
  if (!match) { return {}; }
  let viewBox = match[1].split(' ')
  viewBox = viewBox.map(item => parseFloat(item));
  return { width: viewBox[2], height: viewBox[3] };
}

function calcBoundSize(coordinates) {
  let groupWidth = 0; let groupHeight = 0;
  coordinates.forEach(coordinate => {
    const { x, y, width, height } = coordinate;
    if (groupWidth < x + width) { groupWidth = x + width }
    if (groupHeight < y + height) { groupHeight = y + height }
  })
  return { width: groupWidth, height: groupHeight }
}

function scaleGroupsNumber(groups, scale) {
  const newGroups = []
  groups.forEach(group => newGroups.push({ ...group }))
  return newGroups.map(group => {
    for (const key in group) {
      if (['graphicId', 'compositionId'].includes(key)) {
        group[key] = group[key]
      } else if (typeof group[key] === 'number') {
        group[key] = group[key] * scale
      }
    }
    return group
  })
}


export const mockMashup2 = {
  "id": 2,
  "brandId": 1,
  "name": "mashup",
  "groups": [
    {
      "size": 1,
      "type": "graphic",
      "based": "height",
      "graphicId": 1,
      "marginTop": 0,
      "marginLeft": 0,
      "marginRight": 0.5,
      "marginBottom": 0
    },
    {
      "size": 1,
      "type": "composition",
      "based": "height",
      "marginTop": 0,
      "marginLeft": 0,
      "marginRight": 0,
      "marginBottom": 0,
      "compositionId": 3
    }
  ],
  "thumbnail": null,
  "structure": "horizontal",
  "align": "middle",
  "safePadding": "0.00",
  "minimumWidth": [],
  "isPrivate": false
}

export const mockMashup = {
  "id": 3,
  "brandId": 1,
  "name": "coord",
  "groups": [
    {
      "top": 0,
      "left": 0,
      "size": 1,
      "type": "graphic",
      "based": "width",
      "graphicId": 1
    },
    {
      "top": 0,
      "left": 2,
      "size": 1,
      "type": "composition",
      "based": "width",
      "compositionId": 3
    }
  ],
  "thumbnail": null,
  "structure": "coordinate",
  "align": "middle",
  "safePadding": "0.00",
  "minimumWidth": [],
  "isPrivate": false
}
